﻿//#include "Downloader.h"
//#include "XyNet/Common/Config.h"
//#include "XyNet/Crypto/Sha.h"
//#include "XyNet/Common/Logger.h"
////#include "XyNet/Common/SetMapHelper.h"
//#include "XyNet/Common/StringConverter.h"
//
//XYNET_IMPLEMENT_DEFAULT_SUBJECT(XyNet::Downloader::Observer);
//
//namespace XyNet
//{
//	const int Downloader::Task::ThreadCount = 10;
//	const int Downloader::Task::_blockSize = 65536;
//
//	Downloader::Task::Task(weak_ptr<RpcChannel> channel,
//		const Bytes& link, const FileSystem::Path& downloadPath, bool downloadNow)
//		: _weakChannel(channel), _link(link)
//		, _totalSize(0), _needDownloadSize(0), _downloadedSize(0)
//		, _state(Prepare), _downloadNow(downloadNow)
//		, _prepareTime(0), _downloadTime(0)
//	{
//		_name = link.substr(_hashSize + 1);
//		_path = downloadPath / _name;
//
//		createDownloadDirectories(downloadPath);
//
//		_needPrepareLinkDownloadPathPairs.emplace_back(link, downloadPath);
//		prepareNext();
//	}
//
//	Downloader::Task::Task(weak_ptr<RpcChannel> channel, 
//		const Bytes& link, const Bytes& localLink, bool downloadNow)
//		: _weakChannel(channel), _link(link)
//		, _totalSize(0), _needDownloadSize(0), _downloadedSize(0)
//		, _state(Prepare), _downloadNow(downloadNow)
//		, _prepareTime(0), _downloadTime(0)
//	{
//		_path = Downloader::getLinkPath(localLink);
//		_name = _path.getFilename().toUtf8();
//
//		auto downloadPath = _path.getParentPath();
//		createDownloadDirectories(downloadPath);
//
//		_needPrepareLinkDownloadPathPairs.emplace_back(link, downloadPath);
//		prepareNext();
//	}
//
//	const Bytes& Downloader::Task::getLink() const
//	{
//		return _link;
//	}
//
//	const string& Downloader::Task::getName() const
//	{
//		return _name;
//	}
//
//	const FileSystem::Path& Downloader::Task::getPath() const
//	{
//		return _path;
//	}
//
//	int64 Downloader::Task::getTotalSize() const
//	{
//		//assert(_state != Prepare);
//		return _totalSize;
//	}
//
//	int64 Downloader::Task::getNeedDownloadSize() const
//	{
//		//assert(_state != Prepare);
//		return _needDownloadSize;
//	}
//
//	int64 Downloader::Task::getDownloadedSize() const
//	{
//		//assert(_state != Prepare);
//		return _downloadedSize;
//	}
//
//	double Downloader::Task::getPrepareTime()
//	{
//		assert(_state != Prepare);
//		return _prepareTime;
//	}
//
//	double Downloader::Task::getDownloadTime()
//	{
//		assert(_state == Finish);
//		return _downloadTime;
//	}
//
//	void Downloader::Task::start()
//	{
//		switch (_state)
//		{
//		case Prepare:
//			Logger::getDefault()->logWarning("任务尚未准备完成");
//			break;
//		case Pause:
//			_state = Download;
//			_timer.restart();
//			//Subject<Observer>::getDefault()->notify(
//			//	bind(&Downloader::Observer::OnTaskStarted, _1, shared_from_this()));
//			for (int i = 0; i <= ThreadCount; ++i)
//				downloadNext();
//			break;
//		case Download:
//			Logger::getDefault()->logWarning("任务正在下载中");
//			break;
//		case Finish:
//			Logger::getDefault()->logWarning("任务已经完成");
//			break;
//		default:
//			assert(false);
//		}
//	}
//
//	void Downloader::Task::pause()
//	{
//		switch (_state)
//		{
//		case Prepare:
//			Logger::getDefault()->logWarning("任务尚未准备完成");
//			break;
//		case Pause:
//			Logger::getDefault()->logWarning("任务已经暂停");
//			break;
//		case Download:
//			_state = Pause;
//			//Subject<Observer>::getDefault()->notify(
//			//	bind(&Downloader::Observer::OnTaskParsed, _1, shared_from_this()));
//			break;
//		case Finish:
//			Logger::getDefault()->logWarning("任务已经完成");
//			break;
//		default:
//			assert(false);
//		}
//	}
//
//	Downloader::Task::State Downloader::Task::getState() const
//	{
//		return _state;
//	}
//
//	void Downloader::Task::prepareNext()
//	{
//		// 检查是否都准备完成
//		if (_needPrepareLinkDownloadPathPairs.empty() && 
//			_preparingLinkDownloadPathPairs.empty())
//		{
//			boost::format format("总尺寸: %d, 需要下载的尺寸: %d");
//			format % _totalSize % _needDownloadSize;
//			Logger::getDefault()->log(format.str());
//
//			_prepareTime = _timer.elapsed();
//			_state = Pause;
//			//Subject<Observer>::getDefault()->notify(
//			//	bind(&Downloader::Observer::OnTaskPrepared, _1, shared_from_this()));
//
//			if (_downloadNow)
//				start();
//			return;
//		}
//
//		shared_ptr<RpcChannel> channel;
//		try
//		{
//			channel = _weakChannel.lock();
//			if (!channel)
//			{
//				Logger::getDefault()->logWarning("连接中断");
//				return;
//			}
//		}
//		catch (const exception& e)
//		{
//			XYNET_HANDLE_EXCEPTION(e);
//		}
//
//		// 获取信息
//		for (const auto& pair : _needPrepareLinkDownloadPathPairs)
//		{
//			_preparingLinkDownloadPathPairs.insert(pair);
//
//			DownloadService::GetResourceInfoMethod method;
//			method.getRequest()->set_link(pair.first);
//			method.call(channel, [this]
//			(shared_ptr<DownloadService::GetResourceInfoMethod::Argument> argument)
//			{
//				const auto& link = argument->getRequest()->link();
//				auto iter = _preparingLinkDownloadPathPairs.find(link);
//				//if (iter == _preparingLinkDownloadPathPairs.end())
//				//	return;
//
//				const auto& info = argument->getResponse()->info();
//				FileSystem::Path path;
//				if (iter->second == _path.getParentPath())	// 这边可以给根文件或目录重命名
//					path = iter->second / _name;
//				else
//					path = iter->second / info.name();
//				Logger::getDefault()->log("下载路径: " + path.toUtf8());
//				_preparingLinkDownloadPathPairs.erase(iter);
//
//				if (info.is_file())
//				{
//					addNeedDownloadFile(
//						std::make_shared<DownloadFileInfo>(link, path, info.size(), info.hash()));
//				}
//				else
//				{
//					// 创建目录
//					createDownloadDirectories(path);
//
//					// 查找现有的文件和目录
//					auto iter = path.getDirectoryIterator();
//					set<string> needDeleteChildNames;
//					while (iter.moveNext())
//					{
//						needDeleteChildNames.insert(iter.getCurrent().getFilename().toUtf8());
//					}
//
//					// 处理子信息
//					for (const auto& childInfo : argument->getResponse()->child_infos())
//					{
//						needDeleteChildNames.erase(childInfo.name());
//
//						if (childInfo.is_file())
//						{
//							addNeedDownloadFile(std::make_shared<DownloadFileInfo>(
//								info.hash() + "f" + childInfo.name(), path / childInfo.name(),
//								childInfo.size(), childInfo.hash()));
//						}
//						else
//						{
//							_needPrepareLinkDownloadPathPairs.emplace_back(
//								childInfo.hash() + "d" + childInfo.name(), path);
//						}
//					}
//
//					// 删除多余的文件或目录
//					for (const auto& childName : needDeleteChildNames)
//					{
//						auto childPath = path / childName;
//						FileSystem::Path::remove(childPath);
//					}
//				}
//
//				prepareNext();
//			}, [this]
//			(shared_ptr<DownloadService::GetResourceInfoMethod::Argument> argument)
//			{
//				Logger::getDefault()->log(
//					argument->getController()->getError()._brief + "重试。");
//				prepareNext();
//			});
//		}
//		_needPrepareLinkDownloadPathPairs.clear();
//	}
//
//	void Downloader::Task::downloadNext()
//	{
//		// 暂停
//		if (_state == Pause)
//			return;
//
//		// 检查是否下载完成
//		if (_needDownloadFileInfos.empty() && _downloadingFileInfos.empty())
//		{
//			if (_state != Finish)
//			{
//				_downloadTime += _timer.elapsed();
//				_state = Finish;
//				//Subject<Observer>::getDefault()->notify(
//				//	bind(&Downloader::Observer::OnTaskFinished, _1, shared_from_this()));
//			}
//			return;
//		}
//
//		// 选择一个连接
//		if (!_downloadingFileInfos.empty())
//		{
//			// 前一个下载文件信息一定是没有需要下载的，所以直接选最后一个
//			const auto& fileInfo = _downloadingFileInfos.back();
//			if (!fileInfo->_needDownloadBlockPositions.empty())
//			{
//				getDownloadingFileData(fileInfo);
//				return;
//			}
//		}
//		// 没有可用的正在下载的文件，添加一个
//		if (!_needDownloadFileInfos.empty())
//		{
//			auto fileInfo = _needDownloadFileInfos.front();
//			_downloadingFileInfos.emplace_back(fileInfo);
//			_needDownloadFileInfos.erase(_needDownloadFileInfos.begin());
//			initDownloadFileInfo(fileInfo);
//			getDownloadingFileData(fileInfo);
//		}
//	}
//
//	void Downloader::Task::createDownloadDirectories(const FileSystem::Path& path)
//	{
//		//Logger::getDefault()->log("创建文件夹：" + path.toUtf8());
//		if (FileSystem::Path::isFile(path))
//		{
//			Logger::getDefault()->logWarning("下载路径是文件，已删除");
//			FileSystem::Path::remove(path);
//		}
//		FileSystem::Path::createDirectories(path);
//	}
//
//	void Downloader::Task::addNeedDownloadFile(shared_ptr<DownloadFileInfo> fileInfo)
//	{
//		if (FileSystem::Path::isDirectory(fileInfo->_path))
//		{
//			Logger::getDefault()->logWarning("下载路径是目录，已删除");
//			FileSystem::Path::remove(fileInfo->_path);
//		}
//
//		// 判断是否需要下载并更新尺寸
//		if (fileInfo->_size == 0)
//		{
//			// 空文件处理
//			boost::filesystem::ofstream fstream(fileInfo->_path.getBoostPath());
//		}
//		else
//		{
//			boost::format format("远端哈希: %s, 本地哈希: %s");
//			format % StringConverter::bytesToHexString(fileInfo->_hash) % 
//				StringConverter::bytesToHexString(getFileHash(fileInfo->_path));
//			Logger::getDefault()->log(format.str());
//
//			if (!FileSystem::Path::isExists(fileInfo->_path) ||
//				(fileInfo->_hash != getFileHash(fileInfo->_path)))
//			{
//				FileSystem::Path::remove(fileInfo->_path);
//				_needDownloadSize += fileInfo->_size;
//				_needDownloadFileInfos.emplace_back(fileInfo);
//			}
//			_totalSize += fileInfo->_size;
//		}
//	}
//
//	void Downloader::Task::initDownloadFileInfo(shared_ptr<DownloadFileInfo> fileInfo)
//	{
//		assert(fileInfo->_needDownloadBlockPositions.empty());
//		int64 nextPosition = 0;
//		while (nextPosition < fileInfo->_size)
//		{
//			fileInfo->_needDownloadBlockPositions.emplace_back(nextPosition);
//			nextPosition += _blockSize;
//		}
//	}
//
//	void Downloader::Task::getDownloadingFileData(shared_ptr<DownloadFileInfo> fileInfo)
//	{
//		assert(!fileInfo->_needDownloadBlockPositions.empty());
//
//		shared_ptr<RpcChannel> channel;
//		try
//		{
//			channel = _weakChannel.lock();
//			if (!channel)
//			{
//				Logger::getDefault()->logWarning("连接中断");
//				return;
//			}
//		}
//		catch (const exception& e)
//		{
//			XYNET_HANDLE_EXCEPTION(e);
//		}
//
//		auto pos = fileInfo->_needDownloadBlockPositions.front();
//		fileInfo->_needDownloadBlockPositions.pop_front();
//		fileInfo->_downloadingBlockPositions.insert(pos);
//
//		int downloadSize = numeric_cast<int>(fileInfo->_size - pos);
//		downloadSize = downloadSize < _blockSize ? downloadSize : _blockSize;
//
//		DownloadService::GetFileDataMethod method;
//		auto request = method.getRequest();
//		request->set_file_link(fileInfo->_link);
//		request->set_position(pos);
//		request->set_block_size(downloadSize);
//		method.call(channel, [this]
//		(shared_ptr<DownloadService::GetFileDataMethod::Argument> argument)
//		{
//			auto request = argument->getRequest();
//			auto iter = std::find_if(_downloadingFileInfos.begin(), _downloadingFileInfos.end(),
//				[request](shared_ptr<DownloadFileInfo> fileInfo)->bool
//			{
//				if (fileInfo->_link == request->file_link())
//					return true;
//				return false;
//			});
//			auto fileInfo = *iter;
//
//			const auto& block = argument->getResponse()->block();
//
//			boost::filesystem::ofstream fstream(fileInfo->_path.getBoostPath(),
//				std::ios::out | std::ios::binary | std::ios::app);
//			fstream.write(block.data(), block.size());
//			fstream.close();
//
//			_downloadedSize += block.size();
//			//Subject<Observer>::getDefault()->notify(
//			//	bind(&Downloader::Observer::OnTaskReceivedData, _1, shared_from_this()));
//
//			fileInfo->_downloadingBlockPositions.erase(request->position());
//			if (!fileInfo->_needDownloadBlockPositions.empty())
//			{
//				getDownloadingFileData(fileInfo);
//				return;
//			}
//			else if (fileInfo->_downloadingBlockPositions.empty())   // 文件下载完成
//			{
//				_downloadingFileInfos.remove(fileInfo);
//				createHashFile(fileInfo->_path, fileInfo->_hash);
//			}
//
//			downloadNext();
//		}, [this]
//		(shared_ptr<DownloadService::GetFileDataMethod::Argument> argument)
//		{
//			Logger::getDefault()->log(argument->getController()->getError()._brief + "重试。");
//			downloadNext();
//		});
//	}
//
//	//////////////////////////////////////////////////////////////////////////
//
//	boost::bimap<XyNet::FileSystem::Path, Bytes> Downloader::_dirPathLinkBimap;
//	const size_t Downloader::_hashSize = ceil(Sha::Sha1 / 8 * 1.33333f);
//
//	Downloader::Downloader() {}
//
//	void Downloader::createTask(
//		const string& link, const FileSystem::Path& downloadPath, bool downloadNow)
//	{
//		if (getTask(link))
//			Logger::getDefault()->logWarning("任务已经存在");
//		else
//			_tasks.emplace_back(std::make_shared<Task>(_weakChannel, link, downloadPath, downloadNow));
//	}
//
//	void Downloader::removeTask(const string& link)
//	{
//		auto iter = std::find_if(_tasks.begin(), _tasks.end(),
//			[link](shared_ptr<Task> task)->bool
//		{
//			if (task->getLink() == link)
//				return true;
//			return false;
//		});
//
//		if (iter != _tasks.end())
//			_tasks.erase(iter);
//		else
//			throw XYNET_EXCEPTION("无法找到要删除的任务。");
//	}
//
//	void Downloader::removeFinishedTasks()
//	{
//		_tasks.erase(std::remove_if(_tasks.begin(), _tasks.end(), []
//		(shared_ptr<Task> task)->bool
//		{
//			return task->getState() == Task::Finish;
//		}), _tasks.end());
//	}
//
//	shared_ptr<Downloader::Task> Downloader::getTask(const string& link)
//	{
//		auto iter = std::find_if(_tasks.begin(), _tasks.end(),
//			[link](shared_ptr<Task> task)->bool
//		{
//			if (task->getLink() == link)
//				return true;
//			return false;
//		});
//
//		if (iter != _tasks.end())
//			return *iter;
//		else
//			return nullptr;
//	}
//
//	ConstIterator<shared_ptr<Downloader::Task>> Downloader::getTasksIterator() const
//	{
//		return ConstIterator<shared_ptr<Task>>::makeContainerIterator(&_tasks);
//	}
//
//	string Downloader::getPathLink(const FileSystem::Path& path)
//	{
//		// f、d表示文件或目录
//		assert(FileSystem::Path::isExists(path) && "路径不存在");
//		if (FileSystem::Path::isFile(path))
//			return getDirectoryHash(path.getParentPath()) + "f" + path.getFilename().toUtf8();
//		else
//			return getDirectoryHash(path) + "d" + path.getFilename().toUtf8();
//	}
//
//	FileSystem::Path Downloader::getLinkPath(const string& link)
//	{
//		assert(link.size() > _hashSize);
//		auto dirLink = link.substr(0, _hashSize);
//		auto iter = _dirPathLinkBimap.right.find(dirLink);
//		assert(iter != _dirPathLinkBimap.right.end() && "无法找到连接对应的路径");
//		FileSystem::Path dirPath = iter->second;
//
//		char flag = link[_hashSize];
//		if (flag == 'f')
//			return dirPath / link.substr(_hashSize + 1);
//		else if (flag == 'd')
//			return dirPath;
//		else
//			assert(false && "错误的类型标记。");
//	}
//
//	int Downloader::getHashSize()
//	{
//		return _hashSize;
//	}
//
//	Bytes Downloader::getFileHash(const FileSystem::Path& path)
//	{
//		//assert(path.isFile(path) && "路径指向的不是文件");
//		if (!path.isFile(path))
//			return "";
//
//		auto hashPath = getFileHashPath(path);
//		if (FileSystem::Path::isFile(hashPath))
//		{
//			HashInfo hashInfo;
//			if (hashInfo.ParseFromString(FileSystem::File::readAllBytes(hashPath)))
//			{
//				int64 size = hashInfo.size();
//				int64 lastWriteTime = hashInfo.last_write_time();
//				const Bytes& hash = hashInfo.hash();
//
//				//boost::filesystem::ifstream stream(
//				//	hashPath.getBoostPath(), std::ios::in | std::ios::binary);
//				//int64 size;
//				//int64 lastWriteTime;
//				//Bytes hash(_hashSize, 0);
//				//stream.read((char*)&size, sizeof(size));
//				//stream.read((char*)&lastWriteTime, sizeof(lastWriteTime));
//				//stream.read((char*)hash.data(), hash.size());
//
//				if (FileSystem::Path::getFileSize(path) != size)
//					return createHashFile(path);
//				else if (FileSystem::Path::getLastWriteTimeUtc(path).getTicks() != lastWriteTime)
//					return createHashFile(path);
//				else
//					return hash;
//			}
//			else
//			{
//				return createHashFile(path);
//			}
//		}
//		else
//		{
//			return createHashFile(path);
//		}
//	}
//
//	Bytes Downloader::createHashFile(const FileSystem::Path& path, const Bytes& inputHash)
//	{
//		if (FileSystem::Path::isDirectory(path))
//			FileSystem::Path::remove(path);
//
//		// 获取尺寸，上次修改时间，哈希值
//		auto size = FileSystem::Path::getFileSize(path);
//		auto lastWriteTime = FileSystem::Path::getLastWriteTimeUtc(path).getTicks();
//		auto hash = inputHash;
//		if (hash.empty())
//		{
//			Sha sha(Sha::Sha1);
//			hash = sha.calculateDigest(FileSystem::File::readAllBytes(path));
//		}
//
//		// 写入哈希文件
//		auto hashPath = getFileHashPath(path);
//		FileSystem::Path::createDirectories(hashPath.getParentPath());
//
//		HashInfo hashInfo;
//		hashInfo.set_size(size);
//		hashInfo.set_last_write_time(lastWriteTime);
//		hashInfo.set_hash(hash);
//		FileSystem::File::writeAllBytes(hashPath, hashInfo.SerializeAsString());
//
//		//boost::filesystem::ofstream stream(
//		//	hashPath.getBoostPath(), std::ios::out | std::ios::binary);
//		//stream.write((char*)&size, sizeof(size));
//		//stream.write((char*)&lastWriteTime, sizeof(lastWriteTime));
//		//stream.write(hash.data(), hash.size());
//
//		return hash;
//	}
//
//	const Bytes& Downloader::getDirectoryHash(const FileSystem::Path& path)
//	{
//		auto iter = _dirPathLinkBimap.left.find(path);
//		if (iter != _dirPathLinkBimap.left.end())
//		{
//			return iter->second;
//		}
//		else
//		{
//			assert(FileSystem::Path::isDirectory(path) && "路径指向的不是目录");
//			auto link = Sha(Sha::Sha1).calculateDigest(path.toUtf8());
//			auto result = _dirPathLinkBimap.left.insert(make_pair(path, link));
//			return result.first->second;
//		}
//	}
//
//	FileSystem::Path Downloader::getFileHashPath(const FileSystem::Path& path)
//	{
//		// 获取哈希文件路径
//		auto hashPath = FileSystem::Path::canonical(path);	// 虽然有些影响速度，但稳定性高
//#ifdef XYNET_PLATFORM_WINDOWS
//		auto pathString = hashPath.toUtf8() + ".hash";
//		pathString[pathString.find(':')] = '/';
//		return Config::getTempPath() / "Hash" / pathString;
//#else
//		return Config::getTempPath() / "Hash" / (hashPath + ".hash");
//#endif
//	}
//}